﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
using DevExpress.XtraTab;
using DICOMViewer.Model;
using DICOMViewer.Utility;
using Leadtools.Dicom;
using Leadtools.DicomDemos;
using Leadtools.DicomDemos.Scu.CFind;
using Qiniu.Storage;
using System.Configuration;
using DevExpress.Utils;
using System.Data;

namespace DICOMViewer.UC
{
    public partial class BindPanel : UserControl
    {
        private readonly List<DicomStudy> listLocal = new List<DicomStudy>();
        public ClientConfig clientConfig;
        private List<Requisition> listRequisition;

        public ProgressForm progressForm;
        public DicomServer selectedServer;
        private DicomServer[] serverAry;
        public ServerSettingForm ServerSettingform;

        private readonly List<DicomStudy> studyList = new List<DicomStudy>();

        public BindPanel()
        {
            InitializeComponent();
        }

        public CFind cfind { get; set; }

        /// <summary>
        ///     本地表格双击事件
        /// </summary>
        public event LocalGridDoubleClickedHandler LocalGridDoubleClicked;

        /// <summary>
        ///     DicomServer通讯双击事件
        /// </summary>
        public event ServerGridDoubleClickedHandler ServerGridDoubleClicked;

        private void Cfind_FindComplete(object sender, FindCompleteEventArgs e)
        {
            if (e.Type == FindType.Study)
            {
                studyList.Clear();
                foreach (DicomDataSet ds in e.Datasets)
                {
                    DicomStudy study = new DicomStudy
                    {
                        PatientID = Utils.GetStringValue(ds, DemoDicomTags.PatientID),
                        AccessionNumber = Utils.GetStringValue(ds, DemoDicomTags.AccessionNumber),
                        PatientName = Utils.GetStringValue(ds, DemoDicomTags.PatientName),
                        StudyDate = Utils.GetStringValue(ds, DemoDicomTags.StudyDate),
                        StudyInstanceUID = Utils.GetStringValue(ds, DemoDicomTags.StudyInstanceUID)
                    };
                    studyList.Add(study);
                }
                gridControl_Machine.Invoke(
                    new EventHandler(delegate
                    {
                        gridControl_Machine.DataSource = studyList;
                        gridControl_Machine.RefreshDataSource();
                    }));
            }
        }

        private void btnDicomSearch_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(tbxQuery.Text)) return;
            CFindQuery dcmQuery = new CFindQuery();
            if (cb_QueryConditon.Text == "影像号")
            {
                dcmQuery.AccessionNo = tbxQuery.Text.Trim();
            }
            else if (cb_QueryConditon.Text == "患者编码")
            {
                dcmQuery.PatientID = tbxQuery.Text.Trim();
            }
            else
            {
                return;
            }
            cfind.Find(selectedServer, FindType.Study, dcmQuery, clientConfig.AETitle);
        }

        private void BindPanel_Load(object sender, EventArgs e)
        {
            //追加Cfind_FindComplete用于处理界面
            cfind.FindComplete += Cfind_FindComplete;

            ReFreshOrder();

            ReFreshMachineSetting();

            RefreshLocalGrid();
        }

        public void ReFreshOrder()
        {
            listRequisition = RequisitionDataHelper.Retrive()
                .OrderByDescending(
                    o => string.IsNullOrEmpty(o.AddDicomTime) ? DateTime.Now : DateTime.Parse(o.AddDicomTime))
                .ToList();
            gridControl_order.DataSource = listRequisition;
            gridControl_order.RefreshDataSource();
        }

        public void ReFreshOrder(string orderNumber)
        {
            listRequisition = RequisitionDataHelper.Retrive(orderNumber)
                .OrderByDescending(
                    o => string.IsNullOrEmpty(o.AddDicomTime) ? DateTime.Now : DateTime.Parse(o.AddDicomTime))
                .ToList();
            gridControl_order.DataSource = listRequisition;
            gridControl_order.RefreshDataSource();
        }

        private void ReFreshMachineSetting()
        {
            cb_Server.Properties.Items.Clear();
            //初始化Server下拉框和Server数组
            serverAry = ComSettingReader.getServerConfig();
            clientConfig = ComSettingReader.getClientConfig();
            for (var i = 0; i < serverAry.Length; i++)
            {
                cb_Server.Properties.Items.Add(serverAry[i].AETitle);
            }
            if (cb_Server.Properties.Items.Count > 0)
            {
                cb_Server.SelectedIndex = 0;
            }
            cb_Server.Update();
            selectedServer = serverAry[0];
            studyList.Clear();
            gridControl_Machine.RefreshDataSource();
        }

        /// <summary>
        ///     刷新本地Grid的操作
        /// </summary>
        public void RefreshLocalGrid()
        {
            listLocal.Clear();

            string path = Application.StartupPath + "\\dicomfile";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            var dirAry = Directory.GetDirectories(path);
            if (dirAry == null || dirAry.Length == 0)
            {
                btnBind.Invoke(new EventHandler(delegate { btnBind.Enabled = false; }));
                return;
            }
            foreach (var studyPath in dirAry)
            {
                DicomDataSet ds = new DicomDataSet();
                var DicomDirFilePath = studyPath + "\\DICOMDIR";
                //当DicomDIR不存在，做特定操作！
                if (!File.Exists(DicomDirFilePath))
                {
                }
                ds.Load(DicomDirFilePath, DicomDataSetLoadFlags.None);
                DicomElement patientElement = ds.GetFirstKey(null, true);
                if (patientElement == null)
                {
                    break;
                }
                var lastRowIndex = 0;
                try
                {
                    DicomElement dicomElement;
                    DicomElement patientNameInformation;
                    DicomElement patientIDInformation;
                    DicomElement patientInformation;
                    int i;
                    var row = new string[8];
                    var patientName = "";
                    var patientID = "";
                    // All the information that will be extracted from the studyElement. This method will extract those and 3 other (patientName, patientID and DICOMDIR file name).
                    long[] tags =
                    {
                        DicomTag.StudyDescription, DicomTag.AccessionNumber, DicomTag.StudyDate,
                        DicomTag.StudyInstanceUID
                    };

                    // Get the patient name and ID.
                    patientNameInformation = ds.FindFirstElement(null, DicomTag.PatientName, false);
                    if (patientNameInformation != null)
                        patientName = ds.GetConvertValue(patientNameInformation);

                    patientIDInformation = ds.FindFirstElement(null, DicomTag.PatientID, false);
                    if (patientIDInformation != null)
                        patientID = ds.GetConvertValue(patientIDInformation);


                    while (patientNameInformation != null)
                    {
                        // Get the first Study
                        dicomElement = ds.GetChildKey(patientElement);
                        dicomElement = ds.GetChildElement(dicomElement, true);

                        while (dicomElement != null)
                        {
                            DicomStudy study = new DicomStudy
                            {
                                PatientID = patientID,
                                PatientName = patientName
                            };
                            patientInformation = ds.FindFirstElement(dicomElement, DicomTag.AccessionNumber, true);
                            if (patientInformation != null)
                            {
                                study.AccessionNumber = ds.GetConvertValue(patientInformation);
                            }
                            patientInformation = ds.FindFirstElement(dicomElement, DicomTag.StudyInstanceUID, true);
                            if (patientInformation != null)
                            {
                                study.StudyInstanceUID = ds.GetConvertValue(patientInformation);
                            }
                            patientInformation = ds.FindFirstElement(dicomElement, DicomTag.StudyDate, true);
                            if (patientInformation != null)
                            {
                                study.StudyDate = ds.GetConvertValue(patientInformation);
                                DateTime dtime;
                                if (DateTime.TryParse(study.StudyDate, out dtime))
                                {
                                    study.StudyDate = dtime.ToShortDateString();
                                }
                            }
                            var seriesCount = 0;
                            DicomElement studyinform = ds.GetChildKey(dicomElement);
                            studyinform = ds.GetChildElement(studyinform, true);
                            while (studyinform != null)
                            {
                                seriesCount++;
                                studyinform = ds.GetNextKey(studyinform, true);
                                studyinform = ds.GetChildElement(studyinform, true);
                            }
                            study.SeriesCount = seriesCount;
                            study.DicomDirPath = DicomDirFilePath;
                            study.FileCount = Directory.GetFiles(studyPath).Length - 1;
                            // get to the next study element.
                            dicomElement = ds.GetNextKey(dicomElement, true);
                            dicomElement = ds.GetChildElement(dicomElement, true);
                            listLocal.Add(study);
                        }

                        patientNameInformation = ds.FindNextElement(patientNameInformation, false);
                        if (patientNameInformation != null)
                            patientName = ds.GetConvertValue(patientNameInformation);

                        patientIDInformation = ds.FindNextElement(patientIDInformation, false);
                        if (patientIDInformation != null)
                            patientID = ds.GetConvertValue(patientIDInformation);

                        patientElement = ds.GetNextKey(patientElement, true);
                    }
                }
                catch (Exception exception)
                {
                }
                ds.Dispose();
            }
            gridControl_Local.Invoke(
                new EventHandler(
                    delegate
                    {
                        gridControl_Local.DataSource = listLocal;
                        gridControl_Local.RefreshDataSource();
                    }));
        }


        private void gridControl_Machine_DoubleClick(object sender, EventArgs e)
        {
            //判断是不是在点击行而不是列头
            GridHitInfo hi =
                gridView_Server.CalcHitInfo((sender as Control).PointToClient(MousePosition));

            if (hi.InRow || hi.InRowCell)
            {
                var studyInstanceUID = gridView_Server.GetFocusedRowCellValue("StudyInstanceUID").ToString();
                var patientID = gridView_Server.GetFocusedRowCellValue("PatientID").ToString();
                //传递事件给外部
                if (ServerGridDoubleClicked != null)
                    ServerGridDoubleClicked(sender,
                        new ServerGridDoubleClickedArg {PatientID = patientID, StudyIntanceUID = studyInstanceUID});
            }
        }

        private void gridControl_Local_DoubleClick(object sender, EventArgs e)
        {
            //判断是不是在点击行而不是列头
            GridHitInfo hi =
                gridView_Local.CalcHitInfo((sender as Control).PointToClient(MousePosition));

            if (hi.InRow || hi.InRowCell)
            {
                var studyInstanceUID = gridView_Local.GetFocusedRowCellValue("StudyInstanceUID").ToString();
                var DicomDirPath = gridView_Local.GetFocusedRowCellValue("DicomDirPath").ToString();
                //传递事件给外部
                if (LocalGridDoubleClicked != null)
                    LocalGridDoubleClicked(sender,
                        new LocalGridDoubleClickedArg
                        {
                            DicomDirPath = DicomDirPath,
                            StudyIntanceUID = studyInstanceUID
                        });
            }
        }

        /// <summary>
        ///     删除本地影像集按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rItemBtnDelete_ButtonClick(object sender, ButtonPressedEventArgs e)
        {
            var patientID = gridView_Local.GetFocusedRowCellValue("PatientID")?.ToString() ?? string.Empty;
            var AccessionNumber = gridView_Local.GetFocusedRowCellValue("AccessionNo")?.ToString() ?? string.Empty;
            var PatientName = gridView_Local.GetFocusedRowCellValue("PatientName")?.ToString() ?? string.Empty;
            var popMsg = string.Format("即将删除影像\r\n影像号：{0}\r\n病人编码：{1}\r\n病人姓名：{2}", AccessionNumber, patientID,
                PatientName);
            DialogResult dr = MessageBox.Show(popMsg, "请确认！", MessageBoxButtons.YesNo);
            if (dr == DialogResult.No) return;
            var studyInstaceUID = gridView_Local.GetFocusedRowCellValue("StudyInstanceUID").ToString();
            var path = Application.StartupPath + "\\dicomfile\\" +
                       studyInstaceUID;
            Directory.Delete(path, true);
            RefreshLocalGrid();
            MessageBox.Show("删除完毕！");
        }

        /// <summary>
        ///     压缩图片，压缩Zip，上传图片，绑定申请单！
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnBind_Click(object sender, EventArgs e)
        {
            //获取相关的值
            var uuid = gridView_Requisition.GetFocusedRowCellValue("uuid")?.ToString() ??
                       string.Empty;
            var orderNumber = gridView_Requisition.GetFocusedRowCellValue("OrderNumber")?.ToString() ?? string.Empty;
            if (string.IsNullOrEmpty(orderNumber))
            {
                Console.WriteLine("order number empty return!");
                return;
            }

            var studyInstaceUID = gridView_Local.GetFocusedRowCellValue("StudyInstanceUID")?.ToString() ??
                                  string.Empty;
            if (string.IsNullOrEmpty(studyInstaceUID))
            {
                Console.WriteLine("studyinstance empty return;");
                return;
            }
            //确认是否需要上传
            if (!ConfirmUpload(orderNumber, false)) return;
            //生成文件打开路径
            var path = Application.StartupPath + "\\dicomfile\\" +
                       studyInstaceUID;
            //判断文件是否存在
            if (!Directory.Exists(path))
            {
                MessageBox.Show("所选中的影像集不存在！请重新选择!");
                RefreshLocalGrid();
            }
            
            //获取文件数组
            var filePathAry = Directory.GetFiles(path);
            progressForm = new ProgressForm(FindForm());
            //初始化图像转换器
            ImageConverter imageConverter = CreateImageConverter(filePathAry, uuid, studyInstaceUID,orderNumber);
            //激活图像转换器
            imageConverter.beginConvert();
            progressForm.ShowDialog();
        }

        /// <summary>
        ///     提醒用户是否进行确认是否进行上传操作！
        /// </summary>
        /// <param name="orderNumber">订单号</param>
        /// <param name="isDirectUpload">是否是直接上传</param>
        /// <returns></returns>
        private bool ConfirmUpload(string orderNumber, bool isDirectUpload)
        {
            string msg;
            if (isDirectUpload)
            {
                msg = string.Format("即将上传选中的文件作为申请单（单号：{0}）的影像数据上传！请确认！", orderNumber);
            }
            else
            {
                var AccessionNumber = gridView_Local.GetFocusedRowCellValue("AccessionNumber")?.ToString() ??
                                      string.Empty;
                var PatientID = gridView_Local.GetFocusedRowCellValue("PatientID")?.ToString() ??
                                string.Empty;
                var PatientName = gridView_Local.GetFocusedRowCellValue("PatientName")?.ToString() ??
                                  string.Empty;
                msg = string.Format("即将将影像号：{0}，病人编号：{1},病人姓名:{2}的影像数据作为申请单（单号：{3}）的影像数据上传！请确认！",
                    AccessionNumber, PatientID, PatientName, orderNumber);
            }

            //弹出提示框确认是否需要上传！
            return MessageBox.Show(msg, "提醒", MessageBoxButtons.YesNo) == DialogResult.Yes;
        }

        /// <summary>
        ///     生成图像转换器，并给其赋予后续事件逻辑
        /// </summary>
        /// <param name="filePathAry"></param>
        /// <param name="savePath"></param>
        /// <param name="uuid"></param>
        /// <param name="studyInstaceUID"></param>
        /// <param name="orderNumber"></param>
        /// <returns></returns>
        private ImageConverter CreateImageConverter(string[] filePathAry, string uuid,
            string studyInstaceUID,
            string orderNumber)
        {
            
            ImageConverter imageConverter =
                new ImageConverter(filePathAry, orderNumber, progressForm);
            imageConverter.OnConverCompleted += (s, arg) =>
            {
                //获取上传服务类
                FormUploaderEx uploadEx = GetFormUploader();
                //上传的文件路径
                var savePath = Application.StartupPath + "\\temp\\" + orderNumber + "_dicom.zip";
                //在另一线程启动上传服务类
                StartUpload(uploadEx, savePath, true, uuid, studyInstaceUID, orderNumber);
            }; 
            //已将jpeg压缩和zip压缩写在一起！
            return imageConverter;
        }

        /// <summary>
        ///     构造上传服务类并赋予其进度弹出框事件
        /// </summary>
        /// <returns></returns>
        private FormUploaderEx GetFormUploader()
        {
            FormUploaderEx uploadEx = new FormUploaderEx();
            progressForm = new ProgressForm(FindForm());
            uploadEx.OnUploadProgress += (uploadedBytes, totalBytes) =>
            {
                Invoke(new EventHandler(delegate
                {
                    var percent = 100.0*uploadedBytes/totalBytes;
                    if (uploadedBytes < totalBytes)
                    {
                        progressForm.counterLabel.Text = string.Format("正在上传数据... ({0,7:0.000}%)", percent);
                        progressForm.progressCounter.Value = (int) percent;
                    }
                    else
                    {
                        progressForm.counterLabel.Text = "上传完毕！正在刷新数据！";
                        progressForm.progressCounter.Value = (int) percent;
                        
                    }
                }));
            };
            return uploadEx;
        }

        /// <summary>
        ///     在另一线程上启动上传！
        /// </summary>
        /// <param name="uploadEx">上传服务类</param>
        /// <param name="uploadfile">保存用文件名</param>
        /// <param name="uuid">订单uuid</param>
        /// <param name="studyInstaceUID"></param>
        /// <param name="orderNumber"></param>
        private void StartUpload(FormUploaderEx uploadEx, string uploadfile, bool delAfterDone, string uuid,
            string studyInstaceUID,string orderNumber)
        {
            new Thread(() =>
            {
                if (!progressForm.Visible)
                {
                    new Thread(() =>
                    {
                        progressForm.counterLabel.Text = "正在上传数据...";
                        progressForm.ShowDialog();
                    }).Start();
                }
                bool isGetUploadConfig = uploadEx.TryGetUploadConfig(LoginInfo.Current.Qiniuconfig);
                if (isGetUploadConfig)
                {
                    uploadEx.UploadFile(uploadfile, orderNumber + "_dicom.zip",
                        string.Format("{0}/Weixin_Interface_User/qiniu/dicomCallBack",
                            ConfigurationManager.AppSettings["WeiXinInterFaceUrl"]),
                        string.Format("& uuid={0}&  studyInstanceuid={1}", uuid, studyInstaceUID));
                    if (delAfterDone)
                    {
                        File.Delete(uploadfile);
                    }
                    UpdateFormAfterUpload(orderNumber);
                }
                else
                {
                    UpdateFormAfterUpload(orderNumber);
                    MessageBox.Show("在线获取上传设置失败！请检查网络后重试！");
                }
                
            }).Start();
        }

        private void UpdateFormAfterUpload(string orderNumber)
        {
            this.Invoke(new EventHandler(delegate
            {
                if (!string.IsNullOrEmpty(orderNumber))
                {
                    ReFreshOrder(orderNumber);
                }
                else
                {
                    ReFreshOrder();
                }
                progressForm.DialogResult = DialogResult.Yes;
            }));
        }

        private void btnSetting_Click(object sender, EventArgs e)
        {
            ServerSettingform = new ServerSettingForm();
            ServerSettingform.ShowDialog();
            ReFreshMachineSetting();
        }

        private void cb_Server_SelectedIndexChanged(object sender, EventArgs e)
        {
            studyList.Clear();
            selectedServer = serverAry[cb_Server.SelectedIndex];
            gridControl_Machine.RefreshDataSource();
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            ReFreshOrder();
        }

        private void gridView_Requisition_FocusedRowChanged(object sender, FocusedRowChangedEventArgs e)
        {
            var dataStatus = gridView_Requisition.GetFocusedRowCellValue("DataStatus")?.ToString()??string.Empty;
            if (dataStatus == "初始化")
            {
                btnBind.Enabled = true;
                btnUpload.Enabled = true;
            }
            else
            {
                btnBind.Enabled = false;
                btnUpload.Enabled = false;
            }
        }

        private void TabControl_Bottom_SelectedPageChanged(object sender, TabPageChangedEventArgs e)
        {
            if (TabControl_Bottom.SelectedTabPageIndex == 0)
            {
                gridView_Requisition_FocusedRowChanged(null, null);
            }
            else
            {
                btnBind.Enabled = false;
            }
        }

        /// <summary>
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void repositoryItemButtonEdit1_ButtonClick(object sender,
            ButtonPressedEventArgs e)
        {
            var orderuuid = gridView_Requisition.GetFocusedRowCellValue("uuid").ToString();
            ReportForm form = new ReportForm(orderuuid);
            form.ShowDialog();
        }

        private void btnUpload_Click(object sender, EventArgs e)
        {
            //获取相关的值
            var uuid = gridView_Requisition.GetFocusedRowCellValue("uuid")?.ToString() ??
                       string.Empty;
            var orderNumber = gridView_Requisition.GetFocusedRowCellValue("OrderNumber")?.ToString() ?? string.Empty;
            if (string.IsNullOrEmpty(orderNumber)) return;

            OpenFileDialog ofDia = new OpenFileDialog();
            ofDia.Title = "请选择需要上传的文件！";
            ofDia.DefaultExt = ".zip";
            ofDia.Filter = "Zip文件|*.zip";
            ofDia.Multiselect = false;
            ofDia.InitialDirectory = Application.StartupPath;
            if (ofDia.ShowDialog() == DialogResult.OK)
            {
                if (ConfirmUpload(orderNumber, true))
                {
                    progressForm = new ProgressForm(FindForm());
                    
                    ZipFileConverter convert = CreateZipFileConverter(ofDia.FileName,uuid,orderNumber);
                    convert.beginConvert();
                    progressForm.ShowDialog();
                }
            }
        }

        private ZipFileConverter CreateZipFileConverter(string sourceFile, string uuid,string orderNumber)
        {
            var savePath = Application.StartupPath + "\\temp\\" + orderNumber + "_dicom.zip";
            ZipFileConverter zipConverter =
                new ZipFileConverter(sourceFile, savePath, orderNumber, progressForm);
            zipConverter.OnConverCompleted += (s, arg) =>
            {
                //获取上传服务类
                FormUploaderEx uploadEx = GetFormUploader();
                
                //在另一线程启动上传服务类
                StartUpload(uploadEx, savePath, true, uuid, arg.Result.ToString(), orderNumber);
            };
            //已将jpeg压缩和zip压缩写在一起！
            return zipConverter;
        }

        private void tbxQuery_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 13)
            {
                e.Handled = true;
                btnDicomSearch_Click(null, null);

            }
        }

        private void toolTipController_Local_GetActiveObjectInfo(object sender,
            ToolTipControllerGetActiveObjectInfoEventArgs e)
        {
            string text = string.Empty;
            ToolTipControlInfo info = null;
            GridHitInfo hitInfo;
            if (e.SelectedControl == gridControl_Local)
            {
                text = "双击打开本地影像集！";
                hitInfo = gridView_Local.CalcHitInfo(e.ControlMousePosition);
            }
            else if (e.SelectedControl == gridControl_Machine)
            {
                text = "双击从服务器下载影像集!";
                hitInfo = gridView_Server.CalcHitInfo(e.ControlMousePosition);
            }
            else return;
            if (hitInfo.HitTest == GridHitTest.RowCell)
            {
                object o = hitInfo.HitTest.ToString() + hitInfo.RowHandle.ToString()+hitInfo.Column.Name.ToString();
                info = new ToolTipControlInfo(o, text);
            }
            if (info != null)
                e.Info = info;
        }
    }

    public delegate void LocalGridDoubleClickedHandler(object sender, LocalGridDoubleClickedArg e);

    public delegate void ServerGridDoubleClickedHandler(object sender, ServerGridDoubleClickedArg e);

    public class LocalGridDoubleClickedArg : EventArgs
    {
        public string StudyIntanceUID { get; set; }
        public string DicomDirPath { get; set; }
    }

    public class ServerGridDoubleClickedArg : EventArgs
    {
        public string StudyIntanceUID { get; set; }
        public string PatientID { get; set; }
    }
}